#include <retcode.h>
#include <types.h>
#include <api/libc/alloc.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <hal/hal_gpio.h>
#include <osal/osal.h>
#include <hld/hld_dev.h>
#include <hld/scart/scart.h>
#include <bus/i2c/i2c.h>
#include "scart_mx9671.h"
static char scart_mx9671_name[HLD_MAX_NAME_SIZE]= "SCART_MX9671_0";
static UINT16 g_mx_volume = 0;
void scart_mx9671_dump_reg(struct scart_device *dev)
{
	UINT8 tmp[10];
	UINT32 i;
	MEMSET(tmp, 0x5a, 10);
	tmp[0] = 0;
	i2c_write_read(dev->i2c_type_id, dev->base_addr, tmp, 1, 10);
	SCART_AK_PRINTF("dump mx9671 reg:\n");
	for(i=0; i<10; i++)
		SCART_AK_PRINTF("%02x ", tmp[i]);

	SCART_AK_PRINTF("\n");
}
INT32 scart_mx9671_detach(struct scart_device *dev);
INT32 scart_mx9671_io_control(struct scart_device *dev, INT32 cmd, UINT32 param)
{
	struct scart_mx9671_private * tp = (struct scart_mx9671_private * )dev->priv;
	RET_CODE rlt = SUCCESS;
	UINT8 reg_dirty_list[MX_MAX_REG_LEN];
	UINT8 reg_offset, reg_tgt_val;
	UINT8 tmp_buf[4];
	UINT8 write = 0;
//	if(cmd!=SCART_CHK_STATE)libc_printf("ak op: cmd %08x, param %08x\n", cmd, param);
		
		
	MEMSET(reg_dirty_list, 0, MX_MAX_REG_LEN);
	switch(cmd)
	{
	case SCART_TV_MODE:
		reg_offset = 7;
		if(TV_MODE_RGB==param)
			reg_tgt_val = 3<<3;
		else if(TV_MODE_CVBS==param)
			reg_tgt_val = 0<<3;
		else
			reg_tgt_val = 2<<3;
		tp->reg_val[reg_offset] &= (~(0x03<<3));
		tp->reg_val[reg_offset] |= reg_tgt_val;
		reg_dirty_list[reg_offset] = 1;
		write = 1;
		
		break;
	case SCART_TV_ASPECT:	
		reg_offset = 7;
		if(ASPECT_4_3==param)
			reg_tgt_val = 3;
		else if(ASPECT_16_9==param)
			reg_tgt_val = 1;
		else
			reg_tgt_val = 0;
		tp->reg_val[reg_offset] &= (~0x03);
		tp->reg_val[reg_offset] |= reg_tgt_val;
		reg_dirty_list[reg_offset] = 1;
		write = 1;
		break;
	case SCART_VCR_ASPECT:		
		reg_offset = 9;
		if(ASPECT_4_3==param)
			reg_tgt_val = 3;
		else if(ASPECT_16_9==param)
			reg_tgt_val = 1;
		else
			reg_tgt_val = 0;
		tp->reg_val[reg_offset] &= (~0x03);
		tp->reg_val[reg_offset] |= reg_tgt_val;
		reg_dirty_list[reg_offset] = 1;
		write = 1;
		break;
	case SCART_TV_SOURCE:
		if(SOURCE_STB_IN==param)
		{
			reg_offset = 1;//Audio
			reg_tgt_val = 0;
			tp->reg_val[reg_offset] &= (~0x3);
			tp->reg_val[reg_offset] |= reg_tgt_val;
			reg_dirty_list[reg_offset] = 1;

			reg_offset = 6;//video 
			reg_tgt_val = 0;	
            tp->reg_val[reg_offset] &= (~0x1f);
			tp->reg_val[reg_offset] |= reg_tgt_val;
			reg_dirty_list[reg_offset] = 1;            
		}
		else if(SOURCE_VCR_IN==param)
		{
			reg_offset = 1;//audio
			reg_tgt_val = 0x01;
			tp->reg_val[reg_offset] &= (~0x03);
			tp->reg_val[reg_offset] |= reg_tgt_val;
			reg_dirty_list[reg_offset] = 1;

			reg_offset = 6;//video
			reg_tgt_val = 0x02|0x08;
			tp->reg_val[reg_offset] &= (~0x1f);
			tp->reg_val[reg_offset] |= reg_tgt_val;
			reg_dirty_list[reg_offset] = 1;

            tmp_buf[0] = 0x0e;
            i2c_write_read(dev->i2c_type_id, dev->base_addr, tmp_buf, 1, 1); 

            tmp_buf[0] = (tmp_buf[0] & 0x0C) >> 2;
            
            reg_offset = 7;//Set TV FS
			//reg_tgt_val = 0x12;/////| tmp_buf[0];
            reg_tgt_val = 0x10 | tmp_buf[0];
            tp->reg_val[reg_offset] &= ~0x1B;////(~(0x3<<3));
			tp->reg_val[reg_offset] |= reg_tgt_val;
			reg_dirty_list[reg_offset] = 1;
            
		}
		else
		{
            reg_offset = 1;//Audio
			reg_tgt_val = 2;
			tp->reg_val[reg_offset] &= (~0x3);
			tp->reg_val[reg_offset] |= reg_tgt_val;
			reg_dirty_list[reg_offset] = 1;

			reg_offset = 6;//video 
			reg_tgt_val = 0x03|0x10;	
            tp->reg_val[reg_offset] &= (~0x1f);
			tp->reg_val[reg_offset] |= reg_tgt_val;
			reg_dirty_list[reg_offset] = 1;
		}
		write = 1;
		break;
	case SCART_VCR_SOURCE:
		if(SOURCE_STB_IN==param)
		{
			reg_offset = 1;//Audio
			reg_tgt_val = 0<<2;
			tp->reg_val[reg_offset] &= (~(0x3<<2));
			tp->reg_val[reg_offset] |= reg_tgt_val;
			reg_dirty_list[reg_offset] = 1;

			reg_offset = 8;//vcr video only cvbs.RGB only use input function 
			reg_tgt_val = 0;
			tp->reg_val[reg_offset] &= (~0x7);
			tp->reg_val[reg_offset] |= reg_tgt_val;
			reg_dirty_list[reg_offset] = 1;

		}
		else if(SOURCE_TV_IN==param)
		{
			reg_offset = 1;//Audio
			reg_tgt_val = 2<<2;
			tp->reg_val[reg_offset] &= (~(0x3<<2));
			tp->reg_val[reg_offset] |= reg_tgt_val;
			reg_dirty_list[reg_offset] = 1;

			reg_offset = 8;//video
			reg_tgt_val = 3;
			tp->reg_val[reg_offset] &= (~(0x7));
			tp->reg_val[reg_offset] |= reg_tgt_val;
			reg_dirty_list[reg_offset] = 1;
		
		}
		else
		{
            reg_offset = 1;//Audio
			reg_tgt_val = 1<<2;
			tp->reg_val[reg_offset] &= (~(0x3<<2));
			tp->reg_val[reg_offset] |= reg_tgt_val;
			reg_dirty_list[reg_offset] = 1;

			reg_offset = 8;//video
			reg_tgt_val = 2;
			tp->reg_val[reg_offset] &= (~(0x7));
			tp->reg_val[reg_offset] |= reg_tgt_val;
			reg_dirty_list[reg_offset] = 1;
            
/*			reg_offset = 4;
			reg_tgt_val = 4<<3;
			tp->reg_val[reg_offset] &= (~(0x7<<3));
			tp->reg_val[reg_offset] |= reg_tgt_val;
			reg_dirty_list[reg_offset] = 1;
			
			reg_offset = 6;
			reg_tgt_val = 2<<5;
			tp->reg_val[reg_offset] &= (~(0x3<<5));
			tp->reg_val[reg_offset] |= reg_tgt_val;
			reg_dirty_list[reg_offset] = 1;

			reg_offset = 7;
			reg_tgt_val = 1<<7;
			tp->reg_val[reg_offset] &= (~(0x1<<7));
			tp->reg_val[reg_offset] |= reg_tgt_val;
			reg_dirty_list[reg_offset] = 1;
*/
		}
		write = 1;
		break;		
	case SCART_CHK_STATE:
        write = 0;
		if(param)
		{
			*((UINT32 *)param) = 0;
			tmp_buf[0] = 0x0e;
			i2c_write_read(dev->i2c_type_id, dev->base_addr, tmp_buf, 1, 1);

            tmp_buf[1] = 0x0f;
			i2c_write_read(dev->i2c_type_id, dev->base_addr, tmp_buf+1, 1, 1);

            tmp_buf[2] = 0x07;
			i2c_write_read(dev->i2c_type_id, dev->base_addr, tmp_buf+2, 1, 1);
            
			if(tmp_buf[0]&0x04)
			{
				*((UINT32 *)param) |= SCART_STATE_VCR_IN;
                if((tmp_buf[2] & 0x03) != ((tmp_buf[0] & 0x0C)>>2))
                {
                    reg_offset = 7;
                    reg_tgt_val = ((tmp_buf[0] & 0x0C)>>2);
                    tp->reg_val[reg_offset] &= ~0x3;
                    tp->reg_val[reg_offset] |= reg_tgt_val;
                    reg_dirty_list[reg_offset] = 1; 
                    write = 1;                    
                }
			}
			if(tmp_buf[0]&0x01)
				*((UINT32 *)param) |= SCART_STATE_TV_IN;
		}
		
		break;
	case SCART_AUDIO_MUTE:
		{
			UINT8 orig_vol;
			reg_offset = 2;
			reg_dirty_list[reg_offset] = 1;
            tp->reg_val[reg_offset] &= ~0x01;
            if(param)
			{
                reg_tgt_val = 0;    
            }
			else
			{
                reg_tgt_val = 1;
			}
            tp->reg_val[reg_offset] |= reg_tgt_val;
            write = 1;
		}
		break;

    case SCART_ENTRY_STADNBY:
        reg_offset = 16;
        if(param == 0)
            reg_tgt_val = 1<<6;
        else
            reg_tgt_val = 3<<6;
        
        tp->reg_val[reg_offset] &= (~(0x3<<6));
		tp->reg_val[reg_offset] |= reg_tgt_val;
		reg_dirty_list[reg_offset] = 1;
		write = 1;        
        break;
    case SCART_DETACH_DEV:
        write = 0;
        rlt = scart_mx9671_detach(dev);
        break;
	default: 
		rlt = ERR_FAILUE;
		break;
	}
	if(rlt==SUCCESS)
	{
		if(write)
		{
			for(reg_offset = 0; reg_offset<MX_MAX_REG_LEN; reg_offset++)
			{
				if(reg_dirty_list[reg_offset])
				{
					tmp_buf[0] = reg_offset;
					tmp_buf[1] = tp->reg_val[reg_offset];
					i2c_write(dev->i2c_type_id, dev->base_addr, tmp_buf, 2);
				}
			}
		}
	}
	return rlt;
}

INT32 scart_mx9671_close(struct scart_device *dev)
{
	UINT8 tmp_buf[MX_MAX_REG_LEN];
	
	tmp_buf[0] = 16;
	tmp_buf[1] = 0x40;
	
	i2c_write(dev->i2c_type_id, dev->base_addr, tmp_buf, 2);
	//scart_mx9671_dump_reg(dev);
	return SUCCESS;
}

INT32 scart_mx9671_open(struct scart_device *dev)
{
	struct scart_mx9671_private * tp = (struct scart_mx9671_private * )dev->priv;
	UINT8 tmp_buf[16];
	UINT16 lsr_id;
	UINT32 i;
	UINT32 scart_state = 0;
    INT32  ret = SUCCESS;
    

    tmp_buf[0] = 0x10;
	tmp_buf[1] = tp->reg_val[tmp_buf[0]];
	ret = i2c_write(dev->i2c_type_id, dev->base_addr, tmp_buf, 2);//write reg 16

	tmp_buf[0] = 0x00;
	tmp_buf[1] = tp->reg_val[tmp_buf[0]];
	ret = i2c_write(dev->i2c_type_id, dev->base_addr, tmp_buf, 2);//write reg 0

    tmp_buf[0] = 0x01;
	tmp_buf[1] = tp->reg_val[tmp_buf[0]];
	ret = i2c_write(dev->i2c_type_id, dev->base_addr, tmp_buf, 2);//write reg 1

    tmp_buf[0] = 0x06;
	tmp_buf[1] = tp->reg_val[tmp_buf[0]];
	ret = i2c_write(dev->i2c_type_id, dev->base_addr, tmp_buf, 2);//write reg 6

    tmp_buf[0] = 0x07;
	tmp_buf[1] = tp->reg_val[tmp_buf[0]];
	ret = i2c_write(dev->i2c_type_id, dev->base_addr, tmp_buf, 2);//write reg 7

    tmp_buf[0] = 0x08;
	tmp_buf[1] = tp->reg_val[tmp_buf[0]];
	ret = i2c_write(dev->i2c_type_id, dev->base_addr, tmp_buf, 2);//write reg 8

    tmp_buf[0] = 0x09;
	tmp_buf[1] = tp->reg_val[tmp_buf[0]];
	ret = i2c_write(dev->i2c_type_id, dev->base_addr, tmp_buf, 2);//write reg 9

    tmp_buf[0] = 0x0D;
	tmp_buf[1] = tp->reg_val[tmp_buf[0]];
	ret = i2c_write(dev->i2c_type_id, dev->base_addr, tmp_buf, 2);//write reg 13
	
	if(dev->vcr_callback != (UINT32)NULL)
	{/*If register callback,using interrupt way to detect VCR plug in-out*/
		HAL_GPIO_BIT_DIR_SET(dev->vcr_plug_pos,HAL_GPIO_I_DIR);
		HAL_GPIO_INT_SET(dev->vcr_plug_pos, 1);
		//HAL_GPIO_INT_REDG_SET(dev->vcr_plug_pos, 1);
		HAL_GPIO_INT_FEDG_SET(dev->vcr_plug_pos, 1);
		HAL_GPIO_INT_CLEAR(dev->vcr_plug_pos);
#if(SYS_CHIP_MODULE == ALI_S3602)
        lsr_id = 8;
        osal_interrupt_register_lsr(lsr_id, (ISR_PROC)dev->vcr_callback, (UINT32)dev);
#endif
		
	}
	
#if 0	
	MEMSET(tmp_buf, 0x5a, 10);
	tmp_buf[0] = 0;
	i2c_write_read(dev->i2c_type_id, dev->base_addr, tmp_buf, 1, 10);

	for(i=0; i<10; i++)
		if(tmp_buf[i]!=tp->reg_val[i])
			return ERR_FAILUE;
#endif
	return ret;
}


INT32 scart_mx9671_attach(struct scart_init_param * param)
{	
	struct scart_device *dev;
	struct scart_mx9671_private * tp;
	if(!param)
		return ERR_FAILUE;
	dev = dev_alloc(scart_mx9671_name, HLD_DEV_TYPE_SCART, sizeof(struct scart_device));
	if (dev == NULL)
	{
		PRINTF("Error: Alloc SCART switch device ERROR!\n");
		return ERR_NO_MEM;
	}
		
	dev->base_addr =	param->reserved3;//SCART_AK4707_BASE_ADDR;
	dev->i2c_type_id = param->i2c_type_id;
	dev->vcr_plug_pos = param->vcr_plug_pos;
	dev->vcr_callback = param->vcr_callback;

	if(param->scart_volume <= 7)
		g_mx_volume = param->scart_volume;
	
	dev->priv	=	MALLOC(sizeof(struct scart_mx9671_private));
	MEMSET(dev->priv, 0, sizeof(struct scart_mx9671_private));
	tp = (struct scart_mx9671_private*)dev->priv;
	tp->priv_addr = dev->priv;
	tp->reg_val[0] = 0x40|g_mx_volume<<1|0;
	tp->reg_val[1] = 0x10;
	tp->reg_val[6] = 0x00;
	tp->reg_val[7] = 0x01;
	tp->reg_val[8] = 0x98;
	tp->reg_val[9] = 0x06;  
    tp->reg_val[13] = 0xFE;
    tp->reg_val[16] = 0xC0;

    /* Function point init */
	dev->attach	=	scart_mx9671_attach;
	dev->open	=	scart_mx9671_open;
	dev->close	=	scart_mx9671_close;
	dev->ioctl	=	scart_mx9671_io_control;
	/* Add this device to queue */
	if(dev_register(dev) != SUCCESS)
	{
		PRINTF("Error: Register RF modulator device ERROR!\n");
        return ERR_DEV_ERROR;
	}
	dev->flags = 0;
	scart_mx9671_name[STRLEN(scart_mx9671_name) - 1] ++;
	return SUCCESS;
}

INT32 scart_mx9671_detach(struct scart_device *dev)
{
    struct scart_mx9671_private * tp;
    UINT16 lsr_id;
    INT32 ret;
    
    if(dev != NULL)
    {
        
        if(dev->vcr_callback != (UINT32)NULL)
        {
#if(SYS_CHIP_MODULE == ALI_S3602)
            lsr_id = 8;
    	    osal_interrupt_unregister_lsr(lsr_id, (ISR_PROC)dev->vcr_callback);            
#endif            

        }
        tp = (struct scart_mx9671_private*)dev->priv;
        FREE(tp);
        tp = NULL;
        dev_free(dev);
        dev = NULL;
        ret = SUCCESS;
    }
    else
        ret = ERR_DEV_ERROR;
    
    return ret;
}
